﻿using System.Collections.Generic;
using System.Linq;

namespace dPet.Domain.Services.Implementation
{
	using dPet.Domain.Models;
	using dPet.Domain.Repositories;
	using dPet.Domain.Specifications;
	using Hangerd;

	public class InvoicingDomainService : IInvoicingDomainService
	{
		private readonly IProductCategoryRepository _productCategoryRepository;
		private readonly IProductSubCategoryRepository _productSubCategoryRepository;
		private readonly IProductRepository _productRepository;
		private readonly IInventoryReducingRecordRepository _inventoryReducingRecordRepository;

		public InvoicingDomainService(
			IProductCategoryRepository productCategoryRepository,
			IProductSubCategoryRepository productSubCategoryRepository,
			IProductRepository productRepository,
			IInventoryReducingRecordRepository inventoryReducingRecordRepository)
		{
			_productCategoryRepository = productCategoryRepository;
			_productSubCategoryRepository = productSubCategoryRepository;
			_productRepository = productRepository;
			_inventoryReducingRecordRepository = inventoryReducingRecordRepository;
		}

		public bool HasSameProductBarcodeUnderHospital(string hospitalId, string barcode, Product currentProduct = null)
		{
			if (string.IsNullOrWhiteSpace(barcode))
			{
				return false;
			}

			var spec = ProductSpecifications.HospitalIdEquals(hospitalId)
				& ProductSpecifications.BarcodeEquals(barcode);

			if (currentProduct != null)
			{
				spec &= !ProductSpecifications.IdEquals(currentProduct.Id);
			}

			return _productRepository.GetAll(spec, false).Count() > 0;
		}

		public bool HasSameCategoryNameUnderHospital(string hospitalId, string categoryName, ProductCategory currentCategory = null)
		{
			var spec = ProductCategorySpecifications.HospitalIdEquals(hospitalId)
				& ProductCategorySpecifications.NameEquals(categoryName);

			if (currentCategory != null)
			{
				spec &= !ProductCategorySpecifications.IdEquals(currentCategory.Id);
			}

			return _productCategoryRepository.GetAll(spec, false).Count() > 0;
		}

		public bool HasSameSubCategoryNameUnderCategory(string categoryId, string subCategoryName, ProductSubCategory currentSubCategory = null)
		{
			var spec = SubCategorySpecifications.CategoryIdEquals(categoryId)
				& SubCategorySpecifications.NameEquals(subCategoryName);

			if (currentSubCategory != null)
			{
				spec &= !SubCategorySpecifications.IdEquals(currentSubCategory.Id);
			}

			return _productSubCategoryRepository.GetAll(spec, false).Count() > 0;
		}

		public void AddInventoryByBatch(InventoryBatch batch)
		{
			if (batch.Details.Count == 0)
			{
				throw new HangerdException("入库清单为空");
			}

			var productsFound = new Dictionary<string, Product>();

			foreach (var detail in batch.Details)
			{
				if (!productsFound.ContainsKey(detail.ProductId))
				{
					var product = _productRepository.Get(detail.ProductId, true, p => p.Inventories);

					if (product == null)
					{
						throw new HangerdException("商品信息读取异常:{0}", detail.ProductId);
					}

					productsFound.Add(detail.ProductId, product);
				}

				//记录商品信息
				detail.RecordProductDetail(productsFound[detail.ProductId]);

				//商品入库
				productsFound[detail.ProductId].AddInventory(detail.ExpiryTime, detail.Quantity);
			}
		}

		public SaleOrder CreateSaleOrder(Hospital hospital, MembershipLevel membershipLevel, ICollection<ShoppingCartItem<Product>> shoppingCart, string @operator)
		{
			if (shoppingCart.Count == 0)
			{
				throw new HangerdException("购买列表为空");
			}

			var saleOrder = new SaleOrder(hospital, membershipLevel, @operator);

			foreach (var item in shoppingCart)
			{
				//增加订单行
				saleOrder.AddOrderLine(new SaleOrderLine(item.Item, item.Quantity));

				//商品出库
				item.Item.ReduceInventory(saleOrder, item.Quantity);
			}

			//计算总额
			saleOrder.CalculateTotalAmount();

			return saleOrder;
		}

		public void ReturnInventoryByOrder(OrderBase order)
		{
			//查询该订单的出库记录
			var spec = InventoryReducingRecordSpecifications.HospitalIdEquals(order.HospitalId)
				& InventoryReducingRecordSpecifications.OrderNumberEquals(order.OrderNumber);

			var inventoryReducingRecords = _inventoryReducingRecordRepository.GetAll(spec, false);
			var productsFound = new Dictionary<string, Product>();

			foreach (var record in inventoryReducingRecords)
			{
				if (!productsFound.ContainsKey(record.ProductId))
				{
					var product = _productRepository.Get(record.ProductId, true, p => p.Inventories);

					if (product == null)
					{
						throw new HangerdException("商品信息读取异常:{0}", record.ProductId);
					}

					productsFound.Add(record.ProductId, product);
				}

				//根据出库记录恢复库存
				productsFound[record.ProductId].AddInventory(record.InventoryNumber, record.ReduceQuantity);
			}
		}
	}
}
